export class BundleLoader {
    static url: string = null;
    name: string = '';
    callback: (bundle: cc.AssetManager.Bundle | null) => void = null;

    private deps: Array<BundleLoader> = [];

    constructor(name, callback: (bundle: cc.AssetManager.Bundle | null) => void) {
        this.name = name;
        this.callback = callback;
        this.load();
    }

    private getBundleLoadName() {
        if (BundleLoader.url) {
            return `${BundleLoader.url}/${this.name}`
        } else {
            return this.name;
        }
    }

    load() {
        let name = this.getBundleLoadName();
        cc.assetManager.loadBundle(name, (error, data) => {
            if (error) {
                this.callback(null);
            } else {
                if (data.deps.length > 0) {
                    data.deps.forEach((dep) => {
                        let bundle = new BundleLoader(dep, () => {
                            const index = this.deps.findIndex((el) => el === bundle);
                            this.deps.splice(index, 1);
                            if (this.deps.length === 0) {
                                cc.log(`load bundle: ${this.name}`);
                                this.callback(data);
                            }
                        });
                        this.deps.push(bundle);
                    });
                } else {
                    cc.log(`load bundle: ${this.name}`);
                    this.callback(data);
                }
            }
        });
    }
}

export class LessonInfo {
    id = null;
    name = '';
    pages: Array<PageInfo> = [];
    loaded: boolean = false;
    _bundle: cc.AssetManager.Bundle | null = null;

    constructor(data: Object) {
        if (data) {
            this.id = data['id'];
            this.name = data['name'];
        }
    }

    load(cb) {
        if (!this.loaded) {
            new BundleLoader(this.id, (data) => {
                if (data) {
                    this.loaded = true;
                    this._bundle = data;
                    cb && cb(data);
                } else {
                    this.loaded = false;
                    this._bundle = null;
                }
            });
        } else {
            cb && cb(this._bundle);
        }
    }
}

export class PageInfo {
    id: string = null;
    name: string = null;
    asset: string = null;
    next: string = null;
    lesson: LessonInfo | null = null;

    constructor(data: Object) {
        if (data) {
            this.id = data['id'];
            this.name = data['name'];
            this.asset = data['asset'];
            this.next = data['next'];
        }
    }

    load(cb) {
        this.lesson.load((bundle: cc.AssetManager.Bundle) => {
            let info = bundle.getAssetInfo(this.asset);
            if (info && info.path) {
                const { path } = info;
                bundle.load(path, cc.Prefab, (error, prefab) => {
                    if (error) {
                        cc.error(`load page failed: `, error);
                    } else {
                        cb && cb(prefab);
                    }
                });
            } else {
                cc.error(`无法在bundle/lesson[${this.lesson.id}] 中查找到资源 ${this.asset} `);
            }
        });
    }
}

export class InitInfo {
    entry: string = null;

    constructor(obj: Object) {
        this.entry = obj['entry'];
    }
}

export class GameConfig {
    static data: Array<LessonInfo> = null;
    static initData: InitInfo = null;

    static loadConfig(cb) {
        this._loadRemoteConfig('runtime.json', (runtimeData) => {
            this.initData = new InitInfo(runtimeData.data);
            this._loadRemoteConfig('edu-project.json', (projectJson) => {
                this._loadRemoteConfig('edu-page.json', (pageJson) => {
                    this._loadRemoteConfig('edu-lesson.json', (lessonJson) => {
                        this.data = this.serializationCfg(projectJson, lessonJson, pageJson);
                        cb && cb(this.data);
                    });
                });
            });
        });
    }

    static _loadRemoteConfig(url, cb) {
        cc.loader.loadRes(url, (error, res) => {
            if (error) {
                cc.error(error);
                return;
            }
            let json = res;
            if (res.json) {
                json = res.json;
            }
            cb && cb(json);
        });
    }

    static serializationCfg(projectJson, lessonJson, pageJson) {
        const lessonCfgData = lessonJson.lesson;
        // 把lesson拍平
        let linearData = [];
        const { entry, directory, version } = projectJson;

        function reBuildLessons(projectLesson) {
            // 从edu-lesson.json逆向查找出课程
            let { id, lessons } = projectLesson;
            let lessonIds = [];
            for (let key in lessonCfgData) {
                let lesson = lessonCfgData[key];
                if (lesson.parentId === id) {
                    lessonIds.push(lesson.id);
                }
            }
            // 比较2个数组的差异
            let str1 = lessons.sort().toString();
            let str2 = lessonIds.sort().toString();
            if (str1 !== str2) {
                // 比较出2个结果差异
                let sameIds = {};
                lessonIds.forEach((id) => {
                    if (lessons.find((el) => el === id)) {
                        sameIds[id] = true;
                    }
                });

                let oriLessonDiff = [];
                lessons.forEach((id) => {
                    if (!sameIds[id]) {
                        oriLessonDiff.push(id);
                    }
                });
                if (oriLessonDiff.length > 0) {
                    cc.warn(
                        `edu-project.json中的课程未出现在edu-lesson.json配置中：\n[${oriLessonDiff.toString()}]`,
                    );
                }
                let checkLessonDiff = [];
                lessonIds.forEach((id) => {
                    if (!sameIds[id]) {
                        checkLessonDiff.push(id);
                    }
                });
                if (checkLessonDiff.length > 0) {
                    cc.warn(
                        `edu-lesson.json中的课程未出现在edu-project.json中: \n[${checkLessonDiff.toString()}]`,
                    );
                }
                // 合并差异数据
                let all = lessonIds.concat(lessons);
                return Array.from(new Set(all));
            } else {
                return lessons;
            }
        }

        function circle(allChildren) {
            if (allChildren && Array.isArray(allChildren) && allChildren.length > 0) {
                for (let i = 0; i < allChildren.length; i++) {
                    let childID = allChildren[i];
                    let startData = directory[childID];
                    if (startData) {
                        if (startData.lessons && Array.isArray(startData.lessons)) {
                            // 理想情况是：没有任何警告和错误，才算是数据验证通过
                            const lessons = reBuildLessons(startData);
                            lessons.forEach((lessonID) => {
                                let lessonData = lessonCfgData[lessonID];
                                if (lessonData) {
                                    let lessonInfo = new LessonInfo(lessonData);
                                    let allPagesData = pageJson.data[lessonInfo.id];
                                    if (allPagesData && Array.isArray(allPagesData)) {
                                        allPagesData.forEach((pageData) => {
                                            let pageInfo = new PageInfo(pageData);
                                            pageInfo.lesson = lessonInfo;
                                            lessonInfo.pages.push(pageInfo);
                                        });
                                    }
                                    linearData.push(lessonInfo);
                                } else {
                                    cc.warn(
                                        `无法从edu-lesson.json中找到课程配置：${startData.name}-[${lessonID}]`,
                                    );
                                }
                            });
                        }
                        circle(startData.children);
                    }
                }
            }
        }

        function data2map(data) {
            if (data.children && Array.isArray(data.children)) {
                for (let i = 0; i < data.children.length; i++) {
                    let child = data.children[i];
                    if (child.nodeType === '__edu_lesson') {
                        let lessonInfo = new LessonInfo(child);
                        let allPagesData = pageJson.data[lessonInfo.id];
                        if (allPagesData && Array.isArray(allPagesData)) {
                            allPagesData.forEach((pageData) => {
                                let pageInfo = new PageInfo(pageData);
                                pageInfo.lesson = lessonInfo;
                                lessonInfo.pages.push(pageInfo);
                            });
                        } else {
                            cc.warn(`lesson[${child.id}]没有page`);
                        }
                        linearData.push(lessonInfo);
                    }
                    data2map(child);
                }
            }
        }

        if (version === '2.0.0') {
            circle(entry);
        } else {
            data2map(projectJson);
        }

        return linearData;
    }

    static getBeginPage() {
        // 先查看entry是啥
        const { entry } = this.initData;
        if (entry) {
            // 查找课程
            let lesson: LessonInfo = this.data.find((el) => el.id === entry);
            if (lesson) {
                if (lesson.pages.length > 0) {
                    return lesson.pages[0];
                } else {
                    cc.warn(`课程[${entry}]未找到页面,自动使用第一个页面`);
                    return this._getFirstLessonPage();
                }
            }
            // 查找页面
            for (let i = 0; i < this.data.length; i++) {
                let item: LessonInfo = this.data[i];
                let findPage = item.pages.find((el) => el.id === entry);
                if (findPage) {
                    return findPage;
                }
            }
            cc.warn(`入口[${entry}]无效,自动使用第一个页面`);
            return this._getFirstLessonPage();
        } else {
            // 使用第一个
            return this._getFirstLessonPage();
        }
    }

    static _getFirstLessonPage() {
        if (this.data.length > 0) {
            let firstLesson: LessonInfo = this.data[0];
            if (firstLesson.pages.length > 0) {
                return firstLesson.pages[0];
            } else {
                cc.warn(`起始课程没有page`);
            }
        } else {
            cc.warn('未发现起始page');
        }
        return null;
    }

    // 暂时废弃，链式结构+事件跳转，无法从配置推算出上一页
    static getPreviously(currentPageID: string): PageInfo {
        for (let i = 0; i < this.data.length; i++) {
            let lesson: LessonInfo = this.data[i];
            let pages = lesson.pages;
            for (let j = 0; j < pages.length; j++) {
                let page: PageInfo = pages[j];
                if (currentPageID === page.id) {
                    let preIndex = j - 1;
                    if (preIndex >= 0) {
                        return pages[preIndex];
                    } else {
                        // 到达头部了
                        return null;
                    }
                }
            }
        }
        return null;
    }

    static getNextPage(currentPageID: string): PageInfo {
        for (let i = 0; i < this.data.length; i++) {
            let lesson: LessonInfo = this.data[i];
            let pages = lesson.pages;
            for (let j = 0; j < pages.length; j++) {
                let page: PageInfo = pages[j];
                if (currentPageID === page.id) {
                    // 目前只能在本页内进行跳转
                    return this.getPageByID(page.next);
                    // let nextIndex = j + 1;
                    // if (nextIndex <= pages.length) {
                    //     return pages[nextIndex];
                    // } else {
                    //     // 到达尾部了
                    //     return null;
                    // }
                }
            }
        }
        return null;
    }

    static getPageByID(id: string): PageInfo {
        for (let i = 0; i < this.data.length; i++) {
            let lesson: LessonInfo = this.data[i];
            let pages = lesson.pages;
            for (let j = 0; j < pages.length; j++) {
                let page: PageInfo = pages[j];
                if (id === page.id) {
                    return page;
                }
            }
        }
        return null;
    }

    static getPagePositionInfo(pageID: string): [number, number] {
        let total = 0;
        let cur = 0;
        for (let i = 0; i < this.data.length; i++) {
            let lesson: LessonInfo = this.data[i];
            let pages = lesson.pages;
            for (let j = 0; j < pages.length; j++) {
                let page: PageInfo = pages[j];
                if (pageID === page.id) {
                    cur = j + 1;
                    total = pages.length;
                }
            }
        }
        return [cur, total];
    }
}
